package org.example;


import org.example.MyRateLimiterConstant;
import org.example.myRateLimiter.MyRateLimiter;
import org.springframework.stereotype.Component;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

//限流器工厂 负责生成新的限流器 要求根据名称生成限流器  这里是原型模式  因为限流器是有状态的 所以不能用单例
public class MyRateLimiterFactory {

    // 缓存加载的类和构造器  这里不考虑并发 因为spring启动时才调用  所以不会有并发问题
    private final Map<String, Class<?>> classCache = new HashMap<>();
    private final Map<String, Constructor<?>> constructorCache = new HashMap<>();


    //核心方法 返回新的限流器
    public MyRateLimiter createRateLimiter(String name, int capacity, int rate) throws Exception {
        // 首字母大写
        name = name.substring(0, 1).toUpperCase() + name.substring(1);


        // 尝试从缓存中加载类
        Class<?> clazz = getCachedClass(name);
        if (clazz == null) {
            throw new ClassNotFoundException("Class not found for name: " + name);
        }

        // 尝试从缓存中加载构造器
        Constructor<?> constructor = getCachedConstructor(name, clazz);
        if (constructor == null) {
            throw new NoSuchMethodException("Constructor not found for class: " + clazz.getName());
        }


        //如果这个参数有问题的话 就抛出异常
        if (capacity < 0 || rate < 0) {
            throw new IllegalArgumentException("capacity or rate is less than 0");
        }
        MyRateLimiter rateLimiter = (MyRateLimiter) constructor.newInstance(capacity, rate);


        // 将类和构造器放入缓存中
        classCache.putIfAbsent(name, clazz);
        constructorCache.putIfAbsent(name, constructor);

        return rateLimiter;
    }

    // 从缓存中获取类，如果没有则加载并缓存
    private Class<?> getCachedClass(String name) {
        return classCache.computeIfAbsent(name, key -> {
            try {
                return Class.forName(MyRateLimiterConstant.RATE_LIMITER_PACKAGE_PREFIX + key);
            } catch (ClassNotFoundException e) {
                return null; // 返回 null，调用处抛出异常
            }
        });
    }

    // 从缓存中获取构造器，如果没有则获取并缓存
    private Constructor<?> getCachedConstructor(String name, Class<?> clazz) {
        return constructorCache.computeIfAbsent(name, key -> {
            try {
                return clazz.getConstructor(int.class, int.class);
            } catch (NoSuchMethodException e) {
                return null; // 返回 null，调用处抛出异常
            }
        });
    }
}
